#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
typedef struct _stack stack;
typedef void (*freefn)(void *data);
typedef struct _stack {
	void *elem;
	int elem_size;
	int stack_size;
	int top;
	freefn fn;
}stack;

#define STACK_MIN_SIZE 32
static void stack_expand(stack *s)
{
	printf("%d\n", s->stack_size<<1);
	s->elem = realloc(s->elem, (s->stack_size<<1)*s->elem_size);
	assert(s->elem != NULL);
	s->stack_size <<= 1;
}

void stack_create(stack *s, int elem_size, int stack_size, freefn fn)
{
	assert(s != NULL && elem_size > 0);

	if (stack_size <= 0) stack_size = STACK_MIN_SIZE;

	s->elem = malloc(stack_size*elem_size);

	assert(s->elem != NULL);
	
	s->elem_size = elem_size;
	s->stack_size = stack_size;
	s->top = 0;
	s->fn = fn;
}

void stack_destroy(stack *s)
{
	assert(s != NULL);
	
	if (s->fn != NULL){
		int i;
		for (i = 0; i < s->top; i++) {
			s->fn((char *)s->elem + i*s->elem_size);
		}
	}
	free(s->elem);
}

void stack_push(stack *s, void *data)
{
	assert(s != NULL && data != NULL);

	if (s->top == s->stack_size) {
		stack_expand(s);
	}

	memcpy((char *)s->elem + s->top*s->elem_size, data, s->elem_size);
	s->top++;
}

void stack_pop(stack *s, void *elem)
{
	assert(s != NULL);
	
	s->top--;
	memcpy(elem, (char *)s->elem + s->top*s->elem_size, s->elem_size);
}

void free_string(void *str)
{
	printf("%s\n", (char *)str);
	printf("%s\n", *(char **)str);
	free(*(char **)str);
}

void main()
{
	int i;
	stack s;
	char *tmp = NULL;
	char *string[] = {"adf", "dafa", "degge"};
	stack_create(&s, sizeof(char *), 8, free_string);
	for (i = 0; i < 3; i++) {
		tmp = strdup(string[i]);
		stack_push(&s, &tmp);
	}
	stack_pop(&s, &tmp);
	printf("%s\n", tmp);	
	stack_destroy(&s);
}
